//Shtuchki ot Ivashki (c), 0.0.3, 2024.
use ferrisgram::error::{GroupIteration, Result}; 
use ferrisgram::ext::filters::message;
use ferrisgram::ext::handlers::{CommandHandler, MessageHandler}; 
use ferrisgram::ext::{Context, Dispatcher, Updater};
use ferrisgram::types::LinkPreviewOptions;
use ferrisgram::Bot;
use hashbrown::HashMap;
use std::fs;
use chrono::{Local, DateTime};
 


#[allow(unused)]
#[tokio::main]
async fn main() {
    fs::write("users.txt", ""); 
    fs::write("names.txt", "abc 123");
    fs::write("vars.txt", "0\n0\n");
    let my_key: i64 = ; //ваш chat_id с ботом 

    let bot_token = String::from(""); // Токен
    // This function creates a new bot instance and the error is handled accordingly
    let bot = match Bot::new(&bot_token, None).await {
        Ok(bot) => bot,
        Err(error) => panic!("failed to create bot: {}", error),
    };

    // dispatcher is a part of internal functionality of updater
    // you may use it for adding handlers.
    let mut dispatcher = &mut Dispatcher::new(&bot);

    // add_handler method maps the provided handler in group 0 automatically
    dispatcher.add_handler(CommandHandler::new("start", start));
    //dispatcher.add_handler(CommandHandler::new("history", history));
    // add_handler_to_group is used to map the provided handler to a group manually.
    // note that handler groups are processed in ascending order.
    dispatcher.add_handler_to_group(
        MessageHandler::new(
            echo,
            // This will restrict our echo function to the messages which
            // contain either text or a caption.
            message::Text::filter().or(message::Caption::filter()),
        ),
        1,
    );

    let mut updater = Updater::new(&bot, dispatcher);

    // This method will start long polling through the getUpdates method
    updater.start_polling(true).await;
}

// This is our callable function for the command handler that we declared earlier
// It will be triggered when someone send /start to the bot.
async fn start(bot: Bot, ctx: Context) -> Result<GroupIteration> {
    // Same logic as chat applies on unwrapping effective message here.
    
    let msg = ctx.effective_message.unwrap();
    let chat = ctx.effective_chat.unwrap();
    let mut link_preview_options = LinkPreviewOptions::new();
    link_preview_options.is_disabled = Some(true);
    write_new_user(chat.username.unwrap(), chat.id);
    //println!();
    // Ferrisgram offers some custom helpers which make your work easy
    // Here we have used one of those helpers known as msg.reply
    msg.reply(
        &bot,        "Привет! Это бот, пересылающий сообщения напрямую ваш. Исходный код доступен здесь: [клик](https://clck.ru/34CQpX)", //Hey! I am an echo bot built using [Ferrisgram](https://github.com/ferrisgram/ferrisgram). I will repeat your messages.
    )
    // this method will ensure that our text will be sent with markdown formatting.
    .parse_mode("markdown".to_string())
    .link_preview_options(link_preview_options)
    // You must use this send() method in order to send the request to the API
    .send()
    .await?;

    // GroupIteration::EndGroups will end iteration of groups for an update.
    // This means that rest of the pending groups and their handlers won't be checked
    // for this particular update.
    Ok(GroupIteration::EndGroups)
}

// This is our callable function for our message handler which will be used to
// repeat the text.
async fn echo(bot: Bot, ctx: Context) -> Result<GroupIteration> {
    let my_key: i64 = ; //ваш chat_id с ботом 

    let chat = ctx.effective_chat.unwrap();

    //let data_about_user = String::from("{chat.username} {chat.id}");
    //let a = table.entry(chat.id).or_insert();
    // Same logic as chat applies on unwrapping effective message here.
    let msg = ctx.effective_message.unwrap();
    write_new_msg(chat.username.clone().unwrap(), chat.id, msg.text.clone().unwrap());
    //let string_vars = fs::read_to_string(format!("vars.txt")).unwrap();
    let mut flag_1 = table_vars()[0];
    let mut flag_2 = table_vars()[1];
    //if !write_new_user(chat.username.expect("Cant get user's nickname!"), chat.id){}
        // хз что тут делат}
    if chat.id == my_key{
        let mut buf = String::new();
        match msg.text.clone().unwrap().to_lowercase().as_str(){
            "история" => {
                println!("история");
                bot.send_message(my_key, "В следующей строке введите имя пользователя и кол-во сообщений, которые вы хотите увидеть.".to_owned()).send().await?;
                let mut ost = String::new();
                for i in &table_vars()[2..]{
                    ost += &format!("{i}\n");
                }
                fs::write("vars.txt", format!("0\n1\n{ost}"));

                
            },
            "все пользователи" => {
                println!("все пользователи");
                for (k, v) in get_table(){
                    buf = String::from(format!("{k}  {v}"));
                    bot.send_message(my_key, buf.clone()).send().await?;
                }
            },
            "сменить имя" => {
                println!("сменить имя");
                bot.send_message(my_key, "В следующей строке введите старое имя пользователя и через пробел новое. Вот так: abc123 bfg321".to_owned()).send().await?;
                flag_1 = 1;
                let mut ost = String::new();
                for i in &table_vars()[1..]{
                    ost += &format!("{i}\n");
                }
                fs::write("vars.txt", format!("1\n{ost}"));

            },
            _ => {
                if flag_1 == 1{
                    let txt = msg.text.clone().unwrap();
                    let vv: Vec<&str> = txt.split_whitespace().collect();
                    let old_name = String::from(vv[0]);
                    let new_name = String::from(vv[1]);   
                    change_name(old_name, new_name);
                    bot.send_message(my_key, "Имя изменено!".to_owned()).send().await?;
                    flag_1 = 0;
                    let mut ost = String::new();
                    for i in &table_vars()[1..]{
                        ost += &format!("{i}\n");
                    }
                    fs::write("vars.txt", format!("0\n{ost}"));
                }
                else if flag_2 == 1{
                    let txt = msg.text.clone().unwrap();
                    let vv: Vec<&str> = txt.split_whitespace().collect();
                    for el in history(vv[0].to_string(), vv[1].parse().expect("Неправильно введено число!")){
                        bot.send_message(my_key, el).send().await?;
                    }
                    bot.send_message(my_key, "Выполнено.".to_owned()).send().await?;
                    flag_2 = 0;
                    let mut ost = String::new();
                    for i in &table_vars()[2..]{
                        ost += &format!("{i}\n");
                    }
                    fs::write("vars.txt", format!("0\n0\n{ost}"));
                }
                else{   
                    println!("переадресация");
                    let txt = msg.text.clone().unwrap();
                    let vv: Vec<&str> = txt.split_whitespace().collect();
                    let inp_name = String::from(vv[0]);
                    let mut name = String::new();
                    let hash = get_table_nick();
                    if hash.contains_key(&inp_name){
                        name = get_table_nick().get(&inp_name).unwrap().to_owned();
                    } 
                    else {
                        name = inp_name;
                    }

                    let mut mess = String::new();

                    for i in &vv[1..]{
                        mess += i;
                        mess += " ";
                    }

                    let id = get_table().get(&name).unwrap().to_owned();
                    bot.send_message(id, mess).send().await?;
                }
            },
            }
    }
    else{ //ВРЕМЕННО!!!
        let autor_mes = &chat.username.unwrap();
        let mut mess_prev = String::from(format!("Новое сообщение от: {autor_mes}"));
        if get_table_nick().contains_key(autor_mes){
            mess_prev += &format!(" (aka {})", get_table_nick().get(autor_mes).unwrap());
        }

        bot.send_message(my_key, mess_prev).send().await?;
        
            //copy_message
        bot.forward_message(my_key, msg.chat.id, msg.message_id)
        // You must use this send() method in order to send the request to the API
        .send()
        .await?;
    }   //ВРЕМЕННО!!!
    
    //msg.reply(&bot, &chat.id.to_string()).send().await?;
    // Every api method creates a builder which contains various parameters of that respective method.
    

    // GroupIteration::EndGroups will end iteration of groups for an update.
    // This means that rest of the pending groups and their handlers won't be checked
    // for this particular update.
    Ok(GroupIteration::EndGroups)
}

fn history(name: String, num: u16) -> Vec<String>{  //История сообщения от пользователя
    let str = String::from("не найдена история сообщений пользвателя");// История сообщений от последнего написавшего
    let id = get_table().get(&name).unwrap().to_owned();
    let info_of_person = fs::read_to_string(format!("{name}_{id}.txt"));
    let mut out_v = vec![];
    
    if info_of_person.is_ok(){
        let bind = info_of_person.expect("не найдена история сообщений пользвателя"); // переделать на match
        let mut v: Vec<&str> = bind.split("===================================").collect();
        v.reverse();
        
        let mut c = 0;
        for el in &v[2..]{
            out_v.push(el.to_string()); //выводим результаты
            c+=1;
            if c > num{
                break;
            }
        }
        out_v
    }else{
        out_v.push(str);
        out_v
    }
    
}

fn table_vars() -> Vec<u8>{ //Служебные переменные
    let file = fs::read_to_string("vars.txt").unwrap();
    let v: Vec<&str> = file.split("\n").collect();
    let mut v_for = vec![];
    let ll = v.len();
    println!("{}", &ll);
    let mut l = 1;
    for el in v{
        v_for.push(el.parse().unwrap());
        println!("{} значение", &el);
        l += 1;
        if l == ll{break;}
    }
    println!("{:#?}", &v_for);
    v_for
}

fn change_name(name: String, new: String){ //Смена имени какого-либо пользователя(добавление псевдонима)
    let file = fs::read_to_string("names.txt").unwrap();
    let v: Vec<&str> = file.split("\n").collect();
    println!("{:#?}", &v);
    let mut hash = HashMap::new();
    let mut v_for = vec![];
    let ll = v.len();
    let mut l = 1;
    for el in v{
        v_for = el.split(' ').collect();
        let num = v_for[1].to_string();
        hash.insert(v_for[0].to_string(),num);
        l += 1;
        if l == ll{break;}
    }
    hash.entry(name.clone()).or_insert(new);

    let mut new_file = String::new();

    let mut counter = 1;
    let lenn = hash.len();

    for (k, v) in hash.clone(){
        if counter == lenn{
            new_file += &format!("{k} {v}");
            break;
        }
        counter += 1;
        new_file += &format!("{k} {v}\n");
    }
    fs::write("names.txt", new_file);
    println!("{:#?} после смены", &hash);
}

fn get_table_nick() -> HashMap<String, String>{ //Получение псевдонима
    let file = fs::read_to_string("names.txt").unwrap();
    let v: Vec<&str> = file.split("\n").collect();
    let mut hash = HashMap::new();
    let mut v_for = vec![];
    let mut l = 1;
    let ll = v.len();
    println!("{ll} get_table_nick()");
    for el in v{
        v_for = el.split(' ').collect();
        println!("{:#?}", v_for);
        let num = v_for[0].to_string();
        hash.insert(v_for[1].to_string(),num);
        l += 1;
        if l == ll-1{break;}
    }

    println!("{:#?}", &hash);
    hash
}

fn get_table() -> HashMap<String, i64>{ // Получение данных пользователей
    let file = fs::read_to_string("users.txt").unwrap();
    let v: Vec<&str> = file.split("\n").collect();
    let mut hash = HashMap::new();
    let mut v_for = vec![];
    let mut l = 1;
    println!("{:#?}", &v);
    let ll = v.len();
    for el in v{
        v_for = el.split(' ').collect();
        let num = v_for[1].parse().unwrap();
        hash.insert(v_for[0].to_string(),num);
        l += 1;
        if l == ll{break;}
    }
    println!("{:#?}", &hash);
    hash
}


fn write_new_user(name: String, id: i64) -> bool{  //Добавление нового пользователя
    let mut file_old = fs::read_to_string("users.txt").unwrap();
    if !file_old.contains(&name) && !file_old.contains(&id.to_string()){
        file_old += &format!("{name} {id}\n");
        fs::write("users.txt", file_old.clone());
        println!("{}", file_old);
        fs::write(format!("{name}_{id}.txt"), "");
        true
    }
    else{
        false
    }
}


fn write_new_msg(name: String, id: i64, msg: String){ //Запись сообщения в историю
    let dt = Local::now();
    //println!("{dt}");
    let mut file_old = fs::read_to_string(format!("{name}_{id}.txt")).unwrap();
    file_old += &format!("===================================\n\n{dt}\n\n{msg}\n");
    fs::write(format!("{name}_{id}.txt"), &file_old);
    let mut file_res = fs::read_to_string(format!("{name}_{id}_reserve.txt")).unwrap();
    file_res += &file_old;
    fs::write(format!("{name}_{id}_reserve.txt"), &file_old);
}

